package callbacks

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"
)

// SimpleLogger implements Logger interface with basic logging
type SimpleLogger struct {
	logger *log.Logger
}

func NewSimpleLogger(logger *log.Logger) *SimpleLogger {
	return &SimpleLogger{logger: logger}
}

func (l *SimpleLogger) Info(msg string, fields map[string]interface{}) {
	l.logger.Printf("[INFO] %s %v", msg, fields)
}

func (l *SimpleLogger) Error(msg string, err error, fields map[string]interface{}) {
	l.logger.Printf("[ERROR] %s: %v %v", msg, err, fields)
}

func (l *SimpleLogger) Debug(msg string, fields map[string]interface{}) {
	l.logger.Printf("[DEBUG] %s %v", msg, fields)
}

// InMemoryMetrics implements MetricsCollector interface with in-memory storage
type InMemoryMetrics struct {
	mu      sync.RWMutex
	metrics map[string][]MetricPoint
}

type MetricPoint struct {
	Value     interface{}
	Tags      map[string]string
	Timestamp time.Time
}

func NewInMemoryMetrics() *InMemoryMetrics {
	return &InMemoryMetrics{
		metrics: make(map[string][]MetricPoint),
	}
}

func (m *InMemoryMetrics) RecordMetric(name string, value interface{}, tags map[string]string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	point := MetricPoint{
		Value:     value,
		Tags:      tags,
		Timestamp: time.Now(),
	}

	m.metrics[name] = append(m.metrics[name], point)
}

func (m *InMemoryMetrics) RecordDuration(name string, duration time.Duration, tags map[string]string) {
	m.RecordMetric(fmt.Sprintf("%s.duration", name), duration.Milliseconds(), tags)
}

func (m *InMemoryMetrics) GetMetrics() map[string][]MetricPoint {
	m.mu.RLock()
	defer m.mu.RUnlock()

	// Create a deep copy to avoid concurrent access issues
	result := make(map[string][]MetricPoint)
	for k, v := range m.metrics {
		points := make([]MetricPoint, len(v))
		copy(points, v)
		result[k] = points
	}
	return result
}

// ConsoleProgress implements ProgressReporter interface with console output
type ConsoleProgress struct {
	mu sync.Mutex
}

func NewConsoleProgress() *ConsoleProgress {
	return &ConsoleProgress{}
}

func (p *ConsoleProgress) UpdateProgress(operation string, progress float32, message string) {
	p.mu.Lock()
	defer p.mu.Unlock()

	fmt.Printf("\r%s: %.1f%% - %s", operation, progress, message)
	if progress >= 100 {
		fmt.Println() // New line when complete
	}
}

// CompositeCallback combines multiple callbacks into one
type CompositeCallback struct {
	callbacks []Callback
}

func NewCompositeCallback(callbacks ...Callback) *CompositeCallback {
	return &CompositeCallback{callbacks: callbacks}
}

func (c *CompositeCallback) HandleEvent(ctx context.Context, data *CallbackData) error {
	for _, callback := range c.callbacks {
		if callback.ShouldHandle(data.Event) {
			if err := callback.HandleEvent(ctx, data); err != nil {
				return err
			}
		}
	}
	return nil
}

func (c *CompositeCallback) ShouldHandle(event CallbackEvent) bool {
	for _, callback := range c.callbacks {
		if callback.ShouldHandle(event) {
			return true
		}
	}
	return false
}

// Helper function to create a standard set of callbacks
func NewDefaultCallbacks(logger *log.Logger) *CompositeCallback {
	return NewCompositeCallback(
		NewLoggingCallback(NewSimpleLogger(logger)),
		NewMetricsCallback(NewInMemoryMetrics()),
		NewProgressCallback(NewConsoleProgress()),
	)
}
